package com.chen.test;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.util.LinkedList;
import java.util.List;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;

import com.chen.Shell;
import com.chen.gui.layout.SimplePane;
import com.chen.qq.Context;

/**
 * 
 * @author Chen
 * 
 */
public class ContentPane2 extends SimplePane {

	private static final long serialVersionUID = 7844784735248544882L;

	public static final int CLOSE = 1;
	public static final int MAX = CLOSE << 1;
	public static final int MIN = CLOSE << 2;
	public static final int SET = CLOSE << 3;
	public static final int SKIN = CLOSE << 4;
	public static final int FEED = CLOSE << 5;

	private int sysBtnMode = 0;

	private float gap = 5;

	private int minWidth = 100;

	private JLabel lbTitle;

	protected SysButton btnFeed = new SysButton("feedback.png");
	protected SysButton btnSkin = new SysButton("skin.png");
	protected SysButton btnSet = new SysButton("setting.png");
	protected SysButton btnMin = new SysButton("sysbtn_min.png");
	protected SysButton btnMax = new SysButton("sysbtn_max.png");
	protected SysButton btnClose = new SysButton("sysbtn_close.png");

	private List<JButton> sysBtns = new LinkedList<JButton>();

	private Handler handler = new Handler();

	private Window window;

	private Color backColor = Context.backColor;

	private boolean resizable = true;

	private ImageIcon backImage = null;

	public static void main(String[] args) {
		Shell.run(new ContentPane2());
	}

	public ContentPane2() {
		this(1);
	}

	public ContentPane2(int mode) {
		setSysButton(mode);
		initListener();

		this.setBorder(new PaneBorder());
	}

	public void setSysButton(int mode) {
		if (mode != sysBtnMode && mode > 0 && mode <= 0x3f) {
			for (JComponent btn : sysBtns) {
				remove(btn);
			}

			sysBtnMode = 0;
			if ((CLOSE & mode) > 0) {
				addRight(btnClose);
				sysBtns.add(btnClose);
				sysBtnMode |= CLOSE;
			}
			if ((MAX & mode) > 0) {
				addRight(btnMax);
				sysBtns.add(btnMax);
				sysBtnMode |= MAX;
			}
			if ((MIN & mode) > 0) {
				addRight(btnMin);
				sysBtns.add(btnMin);
				sysBtnMode |= MIN;
			}
			if ((SET & mode) > 0) {
				addRight(btnSet);
				sysBtns.add(btnSet);
				sysBtnMode |= SET;
			}
			if ((SKIN & mode) > 0) {
				addRight(btnSkin);
				sysBtns.add(btnSkin);
				sysBtnMode |= SKIN;
			}
			if ((FEED & mode) > 0) {
				addRight(btnFeed);
				sysBtns.add(btnFeed);
				sysBtnMode |= FEED;
			}
		}
	}

	private void initListener() {
		this.addMouseListener(handler);
		this.addMouseMotionListener(handler);

		btnClose.addActionListener(handler);

		if (btnSkin != null)
			btnSkin.addActionListener(handler);

		if (btnFeed != null)
			btnFeed.addActionListener(handler);

		if (btnSet != null)
			btnSet.addActionListener(handler);

		if (btnMin != null)
			btnMin.addActionListener(handler);

		if (btnMax != null)
			btnMax.addActionListener(handler);
	}

	public void setResizable(boolean resizable) {
		this.resizable = resizable;
	}

	private Window getWindow() {
		if (window == null) {
			window = SwingUtilities.getWindowAncestor(this);
		}

		return window;
	}

	public void setBackColor(Color color) {
		if (color == null)
			color = Context.backColor;

		this.backColor = color;
		repaint();
	}

	public void setBackImage(ImageIcon img) {
		this.backImage = img;
		repaint();
	}

	void setTitle(String title) {
		if (lbTitle != null) {
			lbTitle.setText(title);
		}
	}

	void setIcon(Icon icon) {
		if (lbTitle != null) {
			lbTitle.setIcon(icon);
		}
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);

		Insets insets = getInsets();

		Graphics2D g2d = (Graphics2D) g.create();
		if (backImage != null) {
			g2d.drawImage(backImage.getImage(), 1, 1, getWidth() - 2, 100, null);
		} else {
			g2d.setColor(backColor);
			g2d.fillRoundRect(insets.left, insets.top, getWidth() - insets.left - insets.right, getHeight()
					- insets.top - insets.bottom, 5, 5);
		}
	}

	class SysButton extends JButton {

		private static final long serialVersionUID = 3889297534256337776L;

		private ImageIcon image;

		public SysButton(String iconName) {
			// setOpaque(false);
			setContentAreaFilled(false);
			setBorder(null);
			setIcon(iconName);
		}

		public void setIcon(String iconName) {
			image = Context.getIcon(iconName);
			setIcon(getIcon(0));
			setRolloverIcon(getIcon(1));
			setPressedIcon(getIcon(2));
			setDisabledIcon(getIcon(3));
			setPreferredSize(new Dimension(image.getIconWidth() / 4, image.getIconHeight()));
			image = null;
		}

		private Icon getIcon(int index) {
			int w = image.getIconWidth() / 4;
			int h = image.getIconHeight();
			CropImageFilter cropFilter = new CropImageFilter(index * w, 0, w, h);
			FilteredImageSource producer = new FilteredImageSource(image.getImage().getSource(), cropFilter);
			return new ImageIcon(Toolkit.getDefaultToolkit().createImage(producer));
		}
	}

	class PaneBorder implements Border {

		private int thickness = 1;
		private Color lineColor = Color.DARK_GRAY;
		private int arc = 7;

		@Override
		public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
			if (this.thickness > 0 && g instanceof Graphics2D) {
				Graphics2D g2d = (Graphics2D) g.create();

				g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				g2d.setColor(this.lineColor);
				g2d.setStroke(new BasicStroke(thickness));
				g2d.drawRoundRect(x, y, width - thickness, height - thickness, arc - 2, arc - 2);
				g2d.setColor(Color.LIGHT_GRAY);
				g2d.setStroke(new BasicStroke(1));
				g2d.drawRoundRect(x + 1, y + 1, width - 3, height - 3, arc, arc);
				g2d.dispose();
			}
		}

		@Override
		public Insets getBorderInsets(Component c) {
			return new Insets(thickness, thickness, thickness, thickness);
		}

		@Override
		public boolean isBorderOpaque() {
			return false;
		}
	}

	class Handler extends MouseInputAdapter implements ActionListener {

		private Point pressPoint = null;

		private int offset;

		@Override
		public void mouseMoved(MouseEvent e) {
			if (isMax() || !resizable)
				return;

			Point point = e.getPoint();
			Cursor cursor = getCursor();
			Cursor resizeCursor = getResizeCursor(point);
			if (cursor != resizeCursor)
				setCursor(resizeCursor);
		}

		@Override
		public void mouseExited(MouseEvent e) {
			if (resizable) {
				for (JComponent btn : sysBtns)
					btn.setCursor(Cursor.getDefaultCursor());
			}

			if (pressPoint == null)
				setCursor(null);
		}

		@Override
		public void mousePressed(MouseEvent e) {
			if (e.getButton() == MouseEvent.BUTTON1) {
				pressPoint = e.getPoint();
			}
		}

		@Override
		public void mouseClicked(MouseEvent e) {
			if (e.getClickCount() >= 2 && e.getSource() == ContentPane2.this) {
				doMaxAction();
			}
		}

		@Override
		public void mouseDragged(MouseEvent e) {
			if (isMax() || pressPoint == null)
				return;

			Point dragPoint = e.getPoint();
			int minHeight = 30;
			if (window == null) {
				getWindow();
			}

			if (getCursor() == Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)) {
				offset = dragPoint.y - pressPoint.y;
				int nW = window.getWidth();
				int nH = window.getHeight() - offset;
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				window.setBounds(window.getX(), window.getY() + offset, nW, nH);
			} else if (getCursor() == Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)) {
				int offset = dragPoint.x - pressPoint.x;
				// pressPoint.x += offset;
				// System.out.println(offset);
				int nW = window.getWidth() - offset;
				int nH = window.getHeight();
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				window.setBounds(window.getX() + offset, window.getY(), nW, nH);
			} else if (getCursor() == Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)) {
				int offset = dragPoint.y - pressPoint.y;
				int nW = window.getWidth();
				int nH = window.getHeight() + offset;
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				pressPoint.y += offset;
				window.setSize(nW, nH);
			} else if (getCursor() == Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)) {
				int offset = dragPoint.x - pressPoint.x;
				int nW = window.getWidth() + offset;
				int nH = window.getHeight();
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				pressPoint.x += offset;
				window.setSize(nW, nH);
			} else if (getCursor() == Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)) {
				int xoffset = dragPoint.x - pressPoint.x;
				int yoffset = dragPoint.y - pressPoint.y;
				int nW = window.getWidth() + xoffset;
				int nH = window.getHeight() - yoffset;
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				pressPoint.x += xoffset;
				window.setBounds(window.getX(), window.getY() + yoffset, nW, nH);
			} else if (getCursor() == Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)) {
				int xoffset = dragPoint.x - pressPoint.x;
				int yoffset = dragPoint.y - pressPoint.y;

				int nW = window.getWidth() + xoffset;
				int nH = window.getHeight() + yoffset;
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				pressPoint.x += xoffset;
				pressPoint.y += yoffset;
				window.setBounds(window.getX(), window.getY(), nW, nH);
			} else if (getCursor() == Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)) {
				int xoffset = dragPoint.x - pressPoint.x;
				int yoffset = dragPoint.y - pressPoint.y;

				int nW = window.getWidth() - xoffset;
				int nH = window.getHeight() + yoffset;
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				pressPoint.y += yoffset;
				window.setBounds(window.getX() + xoffset, window.getY(), nW, nH);
			} else if (getCursor() == Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)) {
				int xoffset = dragPoint.x - pressPoint.x;
				int yoffset = dragPoint.y - pressPoint.y;
				int nW = window.getWidth() - xoffset;
				int nH = window.getHeight() - yoffset;
				if (nH <= minHeight || nW < minWidth) {
					return;
				}
				window.setBounds(window.getX() + xoffset, window.getY() + yoffset, nW, nH);
			} else {
				Point point = window.getLocation();
				int xoffset = dragPoint.x - pressPoint.x;
				int yoffset = dragPoint.y - pressPoint.y;
				point.translate(xoffset, yoffset);
				window.setLocation(point);
			}
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			pressPoint = null;
		}

		private boolean isInLeft(Point p) {
			return p.getX() > 0 && p.getX() < gap;
		}

		private boolean isInRight(Point p) {
			Rectangle rect = getBounds();
			return p.getX() < rect.getWidth() && p.getX() > rect.getWidth() - gap;
		}

		private boolean isInTop(Point p) {
			return p.getY() > 0 && p.getY() < gap;
		}

		private boolean isInBottom(Point p) {
			Rectangle rect = getBounds();
			return p.getY() < rect.getHeight() && p.getY() > rect.getHeight() - gap;
		}

		private Cursor getResizeCursor(Point p) {
			boolean l = isInLeft(p);
			boolean r = isInRight(p);
			boolean t = isInTop(p);
			boolean b = isInBottom(p);
			if (l) {
				if (t) {
					return Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR);
				} else if (b) {
					return Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR);
				}
				return Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR);
			} else if (r) {
				if (t) {
					return Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR);
				} else if (b) {
					return Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR);
				}
				return Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
			} else if (b) {
				return Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR);
			} else if (t) {
				return Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR);
			}

			return Cursor.getDefaultCursor();
		}

		private boolean isMax() {
			return false;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			Object source = e.getSource();
			if (source == null)
				return;

			if (source == btnClose) {
				System.exit(0);
			} else if (source == btnMin) {
				JFrame frame = (JFrame) getWindow();
				frame.setExtendedState(JFrame.ICONIFIED);
			} else if (source == btnMax) {
				doMaxAction();
			}
		}

		private void doMaxAction() {
			JFrame frame = (JFrame) getWindow();
			int state = frame.getExtendedState() == JFrame.MAXIMIZED_BOTH ? JFrame.NORMAL
					: JFrame.MAXIMIZED_BOTH;
			if (state == JFrame.NORMAL) {
				btnMax.setIcon("sysbtn_max.png");
			} else {
				btnMax.setIcon("sysbtn_restore.png");
			}

			frame.setExtendedState(state);
		}
	}
}
